﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using VerifyArgs;
using bbv.Common.EventBroker;

namespace Corvus
{
    public class EventBrokerAdapter : IEventBroker, IDisposable
    {

        private ILogger _logger;
        private EventBroker _broker;

        public EventBrokerAdapter(ILogger logger)
        {
            Verify.Args(new { logger }).NotNull();
            _logger = logger;
            _broker = new EventBroker();
        }

        public void Publish(string topic, object sender, EventArgs e)
        {
            Verify.Args(new { topic }).NotNullOrEmpty();
            Verify.Args(new { e }).NotNullOrEmpty();
            string topicUri = StringToUri(topic);
            _logger.Log(this.GetType(), LogLevel.Verbose, "Publishing event '{0}'", topicUri);
            _broker.Fire(topicUri, sender, HandlerRestriction.None, sender, e);

        }

        public void Publish<TEventArgs>(object sender, TEventArgs e) where TEventArgs : EventArgs
        {
            Verify.Args(new { e }).NotNullOrEmpty();
            string topicUri = StringToUri(typeof(TEventArgs).FullName);
            _logger.Log(this.GetType(), LogLevel.Verbose, "Publishing event '{0}'", topicUri);
            _broker.Fire(topicUri, sender, HandlerRestriction.None, sender, e);

        }

        public void Subscribe(string topic, object subscriber, EventHandler handler)
        {
            Verify.Args(new { topic }).NotNullOrEmpty();
            Verify.Args(new { subscriber }).NotNull();
            Verify.Args(new { handler }).NotNull();
            string topicUri = StringToUri(topic);
            _logger.Log(this.GetType(), LogLevel.Verbose, "Subscribing '{1}' to event '{0}'", topicUri, subscriber.GetType());
            _broker.AddSubscription(topicUri, subscriber, handler, new bbv.Common.EventBroker.Handlers.Publisher());
        }

        public void Subscribe<TEventArgs>(object subscriber, EventHandler<TEventArgs> handler) where TEventArgs : EventArgs
        {
            Verify.Args(new { subscriber }).NotNull();
            Verify.Args(new { handler }).NotNull();
            string topicUri = StringToUri(typeof(TEventArgs).FullName);
            _logger.Log(this.GetType(), LogLevel.Verbose, "Subscribing '{1}' to event '{0}'", topicUri, subscriber.GetType());
            _broker.AddSubscription(topicUri, subscriber, handler, new bbv.Common.EventBroker.Handlers.Publisher());
        }

        private const string TopicScheme = "topic://";
        private const string EventArgs = "EventArgs";

        private static string StringToUri(string topicString)
        {
            if (topicString.StartsWith(TopicScheme, StringComparison.OrdinalIgnoreCase)) return topicString;
            if (topicString.EndsWith(EventArgs, StringComparison.OrdinalIgnoreCase)) topicString = topicString.Substring(0, topicString.Length - 9);
            if (!topicString.StartsWith(Constants.Corvus + ".", StringComparison.OrdinalIgnoreCase)) topicString = Constants.Corvus + "." + topicString;
            topicString = topicString.Replace("..", ".");
            return TopicScheme + topicString.Replace('.', '/').ToLowerInvariant().Trim('/');
        }

        #region Disposing Pattern

        private bool _disposed;

        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    _broker.Dispose();
                }
                // Dispose unmanaged resources.
            }
            _disposed = true;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        #endregion
    }
}
